
#include <algorithm>
#include <ctime>
#include <cstdlib>
#include "block.h"

bool Block::initialized = false;

Block* Block::newRandomBlock(int (&area)[AREA_ROW][AREA_COL])
{
    if(!initialized){
        srand(time(0));
        initialized = true;
    }
    return new Block(rand() % 7, area);
}

Block::Block(int idx, int (&area)[AREA_ROW][AREA_COL])
    : gameArea(area)
{
    std::copy(&blocks[idx][0][0], &blocks[idx][0][0]+4*4, &block[0][0]);

    // 计算边界
    findBorder();

    // 设置初始位置
    position.x = AREA_COL/2-2;
    position.y = 0;
}

void Block::findBorder()
{
    int top = 3;
    int bottom = 0;
    int left = 3;
    int right = 0;

    for(int y = 0; y < 4; y ++)
        for(int x = 0; x < 4; x ++)
        {
            if(block[y][x] != 0)
            {
                if(top > y)
                    top = y;
                if(bottom < y)
                    bottom = y;
                if(left > x)
                    left = x;
                if(right < x)
                    right = x;
            }
        }

    border.top = top;
    border.bottom = bottom;
    border.left = left;
    border.right = right;
}

bool Block::canMove(Motion motion)
{
    // 保存数据
    int blockBackup[4][4];
    std::copy(&block[0][0], &block[0][0]+4*4, &blockBackup[0][0]);
    Border borderBackup = border;

    bool result = true;

    int x = position.x;
    int y = position.y;

    switch(motion)
    {
    case Rotate:
        rotate();
        findBorder();   // 旋转后要重新计算边界
        break;
    case MoveDown:
        y += 1;
        break;
    case MoveLeft:
        x -= 1;
        break;
    case MoveRight:
        x += 1;
        break;
    default:
        break;
    }

    if(x + border.left < 0 || x + border.right > AREA_COL-1 ||
            y + border.bottom > AREA_ROW-1)
        result = false;

    for(int i = border.top; i <= border.bottom; i++){
        if(!result)
            break;

        for(int j = border.left; j <= border.right; j++){
            if(gameArea[y+i][x+j] == 2 && block[i][j] == 1)
            {
                result = false;
                break;
            }
        }
    }

    // 恢复数据
    std::copy(&blockBackup[0][0], &blockBackup[0][0]+4*4, &block[0][0]);
    border = borderBackup;

    return result;
}

void Block::rotate()
{
    int temp[4][4];
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
            temp[3-j][i]=block[i][j];

    std::copy(&temp[0][0], &temp[0][0]+4*4, &block[0][0]);
}

void Block::putDown()
{
    for(int i = border.top; i <= border.bottom; i++)
        for(int j = border.left; j <= border.right; j++)
            if(block[i][j]==1)
                gameArea[position.y+i][position.x+j]=2; //x和y别搞反
}

bool Block::moveRotate()
{
    if(!canMove(Rotate))
        return false;

    //逆时针旋转90度
    rotate();

    //重新计算边界
    findBorder();
    return true;
}

bool Block::moveDown()
{
    if(canMove(MoveDown)){
        position.y ++;
        return true;
    }
    return false;
}

bool Block::moveLeft()
{
    if(canMove(MoveLeft)){
        position.x --;
        return true;
    }
    return false;
}

bool Block::moveRight()
{
    if(canMove(MoveRight)){
        position.x ++;
        return true;
    }
    return false;
}
